/** @file

Copyright (c) 2006-2023, Kunlun BIOS, Kunlun Technology (Beijing) Co., Ltd.. All
Rights Reserved.

You may not reproduce, distribute, publish, display, perform, modify, adapt,
transmit, broadcast, present, recite, release, license or otherwise exploit
any part of this publication in any form, by any means, without the prior
written permission of Kunlun Technology (Beijing) Co., Ltd..

**/
#include <InterSetupLib.h>
#include <Protocol/SetupUtilityApplication.h>

EFI_STATUS
EFIAPI
InstallSetupAppProtocol(
  VOID
  );

/**

  Call back the setup application.

  VOID

**/
EFI_STATUS
LibCallSetupApp (
  VOID
  )
{
  EFI_STATUS                               Status;
  UINTN                                    HandleCount;
  EFI_HANDLE                               *HandleBuffer;
  EFI_GUID                                 FileNameGuid;
  MEDIA_FW_VOL_FILEPATH_DEVICE_PATH        FvFilePath;
  UINTN                                    Index;
  EFI_FIRMWARE_VOLUME2_PROTOCOL            *Fv;
  UINTN                                    Size;
  EFI_FV_FILETYPE                          Type;
  EFI_FV_FILE_ATTRIBUTES                   Attributes;
  UINT32                                   AuthenticationStatus;
  EFI_DEVICE_PATH_PROTOCOL                 *DevicePath;
  EFI_DEVICE_PATH_PROTOCOL                 *SetupAppDevicePath;
  EFI_HANDLE                               ImageHandle;
  UINTN                                    ExitDataSize;
  CHAR16                                   *ExitData;
  EFI_SETUP_UTILITY_APPLICATION_PROTOCOL   *SetupUtilityApp;
  EFI_HANDLE                               SetupUtilityHandle;


  HandleCount  = 0;
  HandleBuffer = NULL;
  FileNameGuid = {0x462CAA21, 0x7614, 0x4503, {0x83, 0x6E, 0x8A, 0xB6, 0xF4, 0x66, 0x23, 0x31}};

  SetupUtilityApp = AllocatePool (sizeof(EFI_SETUP_UTILITY_APPLICATION_PROTOCOL));
  if (SetupUtilityApp == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }
  SetupUtilityHandle = 0;
  SetupUtilityApp->VfrDriverState = InitializeSetupUtility;
  SetupUtilityApp->DisplayState = PreparetoDisplay;
  Status = gBS->InstallProtocolInterface (
                  &SetupUtilityHandle,
                  &gEfiSetupUtilityApplicationProtocolGuid,
                  EFI_NATIVE_INTERFACE,
                  SetupUtilityApp
                  );

  Status = gBS->LocateHandleBuffer (
                  ByProtocol,
                  &gEfiFirmwareVolume2ProtocolGuid,
                  NULL,
                  &HandleCount,
                  &HandleBuffer
                  );
  if (Status != EFI_SUCCESS || HandleBuffer == NULL) {
    return EFI_NOT_FOUND;
  }

  EfiInitializeFwVolDevicepathNode (&FvFilePath, &FileNameGuid);

  for (Index = 0; Index < HandleCount; Index++) {
    Status = gBS->HandleProtocol (
                    HandleBuffer[Index],
                    &gEfiFirmwareVolume2ProtocolGuid,
                    (VOID **) &Fv
                    );
    if (!EFI_ERROR (Status)) {
      Status = Fv->ReadFile (
                     Fv,
                     &FileNameGuid,
                     NULL,
                     &Size,
                     &Type,
                     &Attributes,
                     &AuthenticationStatus
                     );
    }
    if (EFI_ERROR (Status)) {
      continue;
    }
gST->ConOut->OutputString (gST->ConOut,L"find file\n");
    //
    // Create device path of setup utility application
    //
    DevicePath = DevicePathFromHandle (HandleBuffer[Index]);
    if (DevicePath == NULL) {
      continue;
    }
    SetupAppDevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &FvFilePath);
    if (SetupAppDevicePath == NULL) {
      continue;
    }
    gST->ConOut->ClearScreen (gST->ConOut);
    gST->ConOut->OutputString (gST->ConOut,L"load image\n");
    Status = InstallSetupAppProtocol();
    Status = gBS->LoadImage (
                    TRUE,
                    gImageHandle,
                    SetupAppDevicePath,
                    NULL,
                    0,
                    &ImageHandle
                    );
    FreePool (SetupAppDevicePath);
    if (EFI_ERROR (Status)) {
      continue;
    }
 gST->ConOut->ClearScreen (gST->ConOut);
 gST->ConOut->OutputString (gST->ConOut,L"load image ok\n");

    gBS->StartImage (ImageHandle, &ExitDataSize, &ExitData);

    break;
  }
  SetupUtilityApp->VfrDriverState = ShutdownSetupUtility;
  gBS->ReinstallProtocolInterface (
         SetupUtilityHandle,
         &gEfiSetupUtilityApplicationProtocolGuid,
         SetupUtilityApp,
         SetupUtilityApp
         );
  gBS->UninstallProtocolInterface (
           SetupUtilityHandle,
           &gEfiSetupUtilityApplicationProtocolGuid,
           SetupUtilityApp
           );
  FreePool (HandleBuffer);

  return Status;
}

/**

  Install the setup app protocol.

  VOID

**/
EFI_STATUS
EFIAPI
InstallSetupAppProtocol (
  VOID
  )
{
  EFI_STATUS       Status;
  EFI_SETUP_UTILITY_APPLICATION_PROTOCOL   *SetupUtilityApp;
  EFI_HANDLE                               SetupUtilityHandle;

  Status = gBS->LocateProtocol (&gEfiSetupUtilityApplicationProtocolGuid, NULL, (VOID **) &SetupUtilityApp);
  if (!EFI_ERROR (Status)) {
    return EFI_ACCESS_DENIED;
  }

  SetupUtilityApp = AllocatePool (sizeof(EFI_SETUP_UTILITY_APPLICATION_PROTOCOL));
  if (SetupUtilityApp == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }
  SetupUtilityHandle = 0;
  SetupUtilityApp->VfrDriverState = InitializeSetupUtility;
  Status = gBS->InstallProtocolInterface (
                  &SetupUtilityHandle,
                  &gEfiSetupUtilityApplicationProtocolGuid,
                  EFI_NATIVE_INTERFACE,
                  SetupUtilityApp
                  );
  return Status;
}


